package eventGenerators;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Random;

import com.jme3.math.FastMath;

import stars.StarModel;
import utilities.Key;

import model.IModel;
import modifiers.FlareProfile;

import eventManager.AppEvent;
import eventManager.EventPortal;

public class SolarFlareGenerator implements IEventGenerator {

	//All generators
	private HashSet<String> events = new HashSet<String>();
	private boolean enabled = true;
	private Key targetKey;
	
	//This specific generator
	private double probability; //[0,1] chance per turn of a flare
	private HashMap<String, Double> probabilityMap = new HashMap<String, Double>();	
	private double severity; //max possible magnitude of a flare
	private HashMap<String, Double> severityMap = new HashMap<String, Double>();
	private double maxSpread; //max spread [0, 2PI] of flares
	private FlareProfile profile; //intensity profile of flares over time
	private Random rand = new Random();
	
	public SolarFlareGenerator(
			Key targetKey,
			double probability,
			double severity,
			double maxSpread,
			FlareProfile profile) {
		
		//register data
		this.targetKey = targetKey;
		this.probability = probability;
		probabilityMap.put("base", probability);
		this.severity = severity;		
		severityMap.put("base", severity);
		this.profile = profile;
		this.maxSpread = maxSpread;
		
		//add events to listen for
		events.add("solarFlareEnable");
		events.add("solarFlareDisable");
		events.add("solarFlareReset");
		events.add("solarFlareChangeProb");
		events.add("solarFlareRevertProb");
		events.add("solarFlareChangeSeverity");
		events.add("solarFlareRevertSeverity");
		events.add("solarFlareChangeProfile");
		events.add("update");
	}
	
	public HashSet<String> getEventTypes() {
		return events;
	}

	public void handleEvent(AppEvent event) {
		String eventName = event.getEventName();
		
		if (eventName.equalsIgnoreCase("update")) {
			//roll dice to determine if solarFlare event is generated, plus mag and direction
			if (enabled) {
				calcFlare();
			}			
		}
		else if (eventName.equalsIgnoreCase("solarFlareEnable")) {
			enable();
		}
		else if (eventName.equalsIgnoreCase("solarFlareDisable")) {
			disable();
		}
		else if (eventName.equalsIgnoreCase("solarFlareReset")) {
			reset();
		}
		else if (eventName.equalsIgnoreCase("solarFlareChangeProb")) {
			Object[] objs = event.getEventObjects();
			String cause = (String) objs[0];
			double prob = (Double) objs[1];
			probability += prob;
			probabilityMap.put(cause, prob);			
		}
		else if (eventName.equalsIgnoreCase("solarFlareRevertProb")) {
			Object[] objs = event.getEventObjects();
			String cause = (String) objs[0];			
			probability += -probabilityMap.get(cause);
			probabilityMap.remove(cause);			
		}
		else if (eventName.equalsIgnoreCase("solarFlareChangeSeverity")) {
			Object[] objs = event.getEventObjects();
			String cause = (String) objs[0];
			double sev = (Double) objs[1];
			severity += sev;
			severityMap.put(cause, sev);
		}
		else if (eventName.equalsIgnoreCase("solarFlareRevertSeverity")) {
			Object[] objs = event.getEventObjects();
			String cause = (String) objs[0];
			severity += -severityMap.get(cause);
			severityMap.remove(cause);
		}
		else if (eventName.equalsIgnoreCase("solarFlareChangeProfile")) {
			Object[] objs = event.getEventObjects();
			FlareProfile profile = (FlareProfile) objs[0];			
			this.profile = profile;
		}
		
		
		
	}

	public void enable() {
		enabled = true;		
	}

	public void disable() {
		enabled = false;		
	}

	public void reset() {
		
	}
	
	//Probabilistically generate flare
	private void calcFlare() {
		double trigger = rand.nextDouble();
		
		if (trigger < probability) {
			double magnitude = severity*profile.getNextMagnitude();
			double spread = rand.nextDouble()*maxSpread;
			double direction = rand.nextDouble()*FastMath.TWO_PI;
			
			Object[] objs = new Object[]{targetKey, magnitude, spread, direction};
			
			EventPortal.queueEvent(new AppEvent("solarFlareEvent", objs));
		}
	}

	public void setTarget(Key targetKey) {
		this.targetKey = targetKey;		
	}
	

}
